package com.wl.cloud.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.wl.cloud.core.dto.DataStoreDTO;
import com.wl.cloud.core.utils.PageUtils;
import com.wl.cloud.core.utils.TreeUtils;
import com.wl.cloud.system.dao.SysResourceCategoryMapper;
import com.wl.cloud.system.dao.SysResourceMapper;
import com.wl.cloud.system.dao.SysRoleResourceMapper;
import com.wl.cloud.system.domain.SysResource;
import com.wl.cloud.system.domain.SysRoleResource;
import com.wl.cloud.system.service.SysResourceService;
import com.wl.cloud.system.support.dto.SysResourceDTO;
import com.wl.cloud.system.support.dto.query.SysResourceQueryDTO;
import com.wl.cloud.system.support.vo.InitSysResourceVO;
import com.wl.cloud.system.support.vo.SysResourceVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 资源表 服务实现类
 *
 * @author wanglin
 * @since 2023-09-18
 */
@Service
public class SysResourceServiceImpl implements SysResourceService {

    @Autowired
    private SysResourceMapper sysResourceMapper;
    @Autowired
    private SysRoleResourceMapper roleResourceMapper;

    @Autowired
    private SysResourceCategoryMapper categoryMapper;

    @Transactional(readOnly = true)
    @Override
    public DataStoreDTO<SysResourceVO> page(Pageable pageable, SysResourceQueryDTO queryDto) {
        QueryWrapper<SysResource> queryWrapper = this.buildQuery(queryDto);
        Page<SysResource> page = PageUtils.transferPage(pageable);
        Page<SysResource> result = this.sysResourceMapper.selectPage(page, queryWrapper);
        return new DataStoreDTO(result.getTotal(), this.transferVo(result.getRecords()));
    }

    @Transactional(readOnly = true)
    @Override
    public DataStoreDTO<SysResourceVO> resourcePage(Pageable pageable, SysResourceQueryDTO queryDto) {
        IPage<SysResourceVO> result = this.sysResourceMapper.selectResourcePage(PageUtils.transferPage(pageable), queryDto);
        return new DataStoreDTO(result.getTotal(), result.getRecords());
    }

    @Transactional(readOnly = true)
    @Override
    public List<SysResourceVO> list(Sort sort, SysResourceQueryDTO queryDto) {
        QueryWrapper<SysResource> queryWrapper = this.buildQuery(queryDto);
        PageUtils.transferSort(queryWrapper, sort);
        return this.transferVo(this.sysResourceMapper.selectList(queryWrapper));
    }

    @Transactional(readOnly = true)
    @Override
    public List<SysResourceVO> resourceList(Sort sort, SysResourceQueryDTO queryDto) {
//        QueryWrapper<SysResource> queryWrapper = this.buildQuery(queryDto);
//        PageUtils.transferSort(queryWrapper, sort);
//        return this.transferVo(this.sysResourceMapper.selectResourcePage(queryDto));
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void save(SysResourceDTO dto) {
        //唯一性验证 name, url
        List<SysResource> resourceList = validateParams(dto.getName(), dto.getUrl());
        if (CollUtil.isNotEmpty(resourceList)) {
            resourceList.stream().forEach(e -> {
                if (dto.getName().equals(e.getName())) {
                    Assert.isTrue(Boolean.FALSE, "资源名称: " + dto.getName() + "已存在");
                }
                if (dto.getUrl().equals(e.getUrl())) {
                    Assert.isTrue(Boolean.FALSE, "资源路径: " + dto.getUrl() + "已存在");
                }
            });
        }
        //验证资源类型是否存在
        Assert.notNull(categoryMapper.selectById(dto.getCategoryId()), "该资源类型不存在");
        dto.setId(null);
        sysResourceMapper.insert(this.transferEntity(null, dto));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void update(SysResourceDTO dto) {
        Assert.hasText(dto.getId(), "id不能为空");
        SysResource entity = sysResourceMapper.selectById(dto.getId());
        Assert.notNull(entity, "找不到id为: " + dto.getId() + " 的记录");

        //唯一性验证 name, url
        List<SysResource> resourceList = validateParams(dto.getName(), dto.getUrl());
        if (CollUtil.isNotEmpty(resourceList)) {
            resourceList.stream().forEach(e -> {
                if (dto.getName().equals(e.getName())) {
                    Assert.isTrue(dto.getId().equals(e.getId()), "资源名称: " + dto.getName() + "已存在");
                }
                if (dto.getUrl().equals(e.getUrl())) {
                    Assert.isTrue(dto.getId().equals(e.getId()), "资源路径: " + dto.getUrl() + "已存在");
                }
            });
        }
        sysResourceMapper.updateById(this.transferEntity(entity, dto));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Set<String> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return;
        }
        //资源是否关联角色
        LambdaQueryWrapper<SysRoleResource> queryWrapper = new LambdaQueryWrapper<SysRoleResource>().in(SysRoleResource::getResourceId, ids);
        List<SysRoleResource> resourceList = roleResourceMapper.selectList(queryWrapper);
        Assert.isTrue(CollUtil.isEmpty(resourceList), "删除的资源已绑定角色，请先删除绑定关系！");
        //删除资源表数据
        sysResourceMapper.deleteBatchIds(ids);
    }

    @Transactional(readOnly = true)
    @Override
    public DataStoreDTO<SysResourceVO> treeResourcePage(Pageable pageable, SysResourceQueryDTO queryDto) {
        IPage<SysResourceVO> pageResult = sysResourceMapper.selectTreeResourcePage(PageUtils.transferPage(pageable), queryDto);
        return new DataStoreDTO(pageResult.getTotal(), pageResult.getRecords());
    }

    @Override
    public List<SysResourceVO> treeResourceList() {
        List<SysResourceVO> voList = sysResourceMapper.selectResourceTreeAll();
        return TreeUtils.generateTrees(voList);
    }

    @Transactional(readOnly = true)
    @Override
    public List<InitSysResourceVO> getInitSysResourceList() {
        //同一URL可能多个角色
        List<InitSysResourceVO> resourceList = sysResourceMapper.getInitSysResourceList();
        return resourceList;
    }

    @Transactional(readOnly = true)
    @Override
    public SysResourceVO get(String id) {
        Assert.hasText(id, "id不能为空");
        SysResource entity = sysResourceMapper.selectById(id);
        Assert.notNull(entity, "找不到id为 " + id + " 的记录");
        return this.transferVo(entity);
    }

    private List<SysResource> validateParams(String name, String url) {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        QueryWrapper<SysResource> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(SysResource::getUrl, url)
                .or().eq(SysResource::getName, name);
        return sysResourceMapper.selectList(queryWrapper);
    }


    private SysResource checkByUrl(String url) {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        QueryWrapper<SysResource> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(SysResource::getUrl, url);
        return sysResourceMapper.selectOne(queryWrapper);
    }

    private SysResource checkByName(String name) {
        if (StringUtils.isBlank(name)) {
            return null;
        }
        QueryWrapper<SysResource> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(SysResource::getName, name);
        return sysResourceMapper.selectOne(queryWrapper);
    }

    private QueryWrapper<SysResource> buildQuery(SysResourceQueryDTO queryDto) {
        QueryWrapper<SysResource> queryWrapper = new QueryWrapper<>();
        if (Objects.nonNull(queryDto)) {
            queryWrapper.lambda()
                    .eq(StringUtils.isNotBlank(queryDto.getId()), SysResource::getId, queryDto.getId())
                    .like(StringUtils.isNotBlank(queryDto.getName()), SysResource::getName, queryDto.getName())
                    .ge(StringUtils.isNotBlank(queryDto.getStartCreateTime()), SysResource::getCreateTime, queryDto.getStartCreateTime())
                    .le(StringUtils.isNotBlank(queryDto.getEndCreateTime()), SysResource::getCreateTime, queryDto.getEndCreateTime());
        }
        return queryWrapper;
    }

    private SysResource transferEntity(SysResource entity, SysResourceDTO dto) {
        if (Objects.isNull(entity)) {
            entity = new SysResource();
        }
        BeanUtils.copyProperties(dto, entity);
        return entity;
    }

    private List<SysResourceVO> transferVo(List<SysResource> entities) {
        if (CollectionUtils.isEmpty(entities)) {
            return Lists.newArrayList();
        }

        List<SysResourceVO> voList = entities.stream().map(entity -> {
            SysResourceVO vo = new SysResourceVO();
            BeanUtils.copyProperties(entity, vo);
            return vo;
        }).collect(Collectors.toList());
        return voList;
    }

    private SysResourceVO transferVo(SysResource entity) {
        if (Objects.isNull(entity)) {
            return null;
        }
        SysResourceVO vo = new SysResourceVO();
        BeanUtils.copyProperties(entity, vo);
        return vo;
    }
}
